/*
 * Copyright (c) 1995, 2022, Oracle and/or its affiliates. All rights reserved.
 * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 */

package java.lang;

import java.io.*;
import java.util.StringTokenizer;
import sun.reflect.CallerSensitive;
import sun.reflect.Reflection;

/**
 * 每个 Java 应用程序都有一个 <code>Runtime</code> 类的单一实例，
 * 允许应用程序与运行应用程序的环境进行接口。
 * 可以从 <code>getRuntime</code> 方法获得当前运行时。
 * <p>
 * 应用程序不能创建自己的此类实例。
 *
 * @author  unascribed
 * @see     java.lang.Runtime#getRuntime()
 * @since   JDK1.0
 */

public class Runtime {
    private static Runtime currentRuntime = new Runtime();

    /**
     * 返回与当前 Java 应用程序关联的运行时对象。
     * <code>Runtime</code> 类的大多数方法都是实例方法，
     * 必须针对当前运行时对象调用。
     *
     * @return  与当前 Java 应用程序关联的 <code>Runtime</code> 对象
     */
    public static Runtime getRuntime() {
        return currentRuntime;
    }

    /** Don't let anyone else instantiate this class */
    private Runtime() {}

    /**
     * 通过启动其关闭序列来终止当前运行的 Java 虚拟机。
     * 此方法从不正常返回。参数用作状态代码；
     * 按照惯例，非零状态代码表示异常终止。
     *
     * <p> 所有已注册的 {@linkplain #addShutdownHook 关闭钩子}（如果有）
     * 都以某种未指定的顺序启动，并允许并发运行直到它们完成。
     * 完成后，虚拟机 {@linkplain #halt 停止}。
     *
     * <p> 如果在所有关闭钩子都已运行后调用此方法且状态为非零，
     * 则此方法使用给定的状态代码停止虚拟机。否则，此方法无限期阻塞。
     *
     * <p> {@link System#exit(int) System.exit} 方法是调用此方法的
     * 常规和便捷方式。
     *
     * @param  status
     *         终止状态。按照惯例，非零状态代码表示异常终止。
     *
     * @throws SecurityException
     *         如果存在安全管理器且其 {@link SecurityManager#checkExit checkExit}
     *         方法不允许使用指定状态退出
     *
     * @see java.lang.SecurityException
     * @see java.lang.SecurityManager#checkExit(int)
     * @see #addShutdownHook
     * @see #removeShutdownHook
     * @see #halt(int)
     */
    public void exit(int status) {
        SecurityManager security = System.getSecurityManager();
        if (security != null) {
            security.checkExit(status);
        }
        Shutdown.exit(status);
    }

    /**
     * 注册一个新的虚拟机关闭钩子。
     *
     * <p> Java 虚拟机<i>关闭</i>是响应两种事件：
     *
     *   <ul>
     *
     *   <li> 程序<i>正常退出</i>，当最后一个非守护线程退出时或当调用
     *   {@link #exit exit}（等效于 {@link System#exit(int) System.exit}）方法时，或
     *
     *   <li> 虚拟机被<i>终止</i>以响应用户中断，例如键入 {@code ^C}，
     *   或系统范围的事件，例如用户注销或系统关闭。
     *
     *   </ul>
     *
     * <p> <i>关闭钩子</i>只是一个已初始化但未启动的线程。
     * 当虚拟机开始其关闭序列时，它将以某种未指定的顺序启动所有已注册的关闭钩子，
     * 并让它们并发运行。当所有钩子都完成时，它将停止。
     * 请注意，守护线程将在关闭序列期间继续运行，
     * 如果关闭是通过调用 {@link #exit exit} 方法启动的，非守护线程也会继续运行。
     *
     * <p> 一旦关闭序列开始，只能通过调用 {@link #halt halt} 方法来停止它，
     * 该方法强制终止虚拟机。
     *
     * <p> 一旦关闭序列开始，就不可能注册新的关闭钩子或取消注册先前注册的钩子。
     * 尝试执行这些操作中的任何一个都会导致抛出 {@link IllegalStateException}。
     *
     * <p> 关闭钩子在虚拟机生命周期的微妙时刻运行，因此应该进行防御性编码。
     * 特别是，它们应该被编写为线程安全的，并尽可能避免死锁。
     * 它们也不应该盲目依赖可能已注册自己的关闭钩子的服务，
     * 因此这些服务本身可能正在关闭过程中。
     * 尝试使用其他基于线程的服务（例如 AWT 事件分派线程）可能会导致死锁。
     *
     * <p> 关闭钩子也应该快速完成其工作。当程序调用 {@link #exit exit} 时，
     * 期望虚拟机将迅速关闭并退出。当虚拟机由于用户注销或系统关闭而终止时，
     * 底层操作系统可能只允许固定的时间来关闭和退出。
     * 因此，不建议在关闭钩子中尝试任何用户交互或执行长时间运行的计算。
     *
     * <p> 关闭钩子中的未捕获异常的处理方式与任何其他线程中的处理方式相同，
     * 通过调用线程的 {@link ThreadGroup} 对象的
     * {@link ThreadGroup#uncaughtException uncaughtException} 方法。
     * 此方法的默认实现将异常的堆栈跟踪打印到 {@link System#err} 并终止线程；
     * 它不会导致虚拟机退出或停止。
     *
     * <p> 在极少数情况下，虚拟机可能会<i>中止</i>，即停止运行而不干净地关闭。
     * 当虚拟机被外部终止时会发生这种情况，例如在 Unix 上使用 {@code SIGKILL} 信号
     * 或在 Microsoft Windows 上使用 {@code TerminateProcess} 调用。
     * 如果本机方法出错，例如损坏内部数据结构或尝试访问不存在的内存，
     * 虚拟机也可能中止。如果虚拟机中止，则无法保证是否会运行任何关闭钩子。
     *
     * @param   hook
     *          已初始化但未启动的 {@link Thread} 对象
     *
     * @throws  IllegalArgumentException
     *          如果指定的钩子已经注册，或者可以确定钩子已经在运行或已经运行过
     *
     * @throws  IllegalStateException
     *          如果虚拟机已经在关闭过程中
     *
     * @throws  SecurityException
     *          如果存在安全管理器且它拒绝 {@link RuntimePermission}{@code ("shutdownHooks")}
     *
     * @see #removeShutdownHook
     * @see #halt(int)
     * @see #exit(int)
     * @since 1.3
     */
    public void addShutdownHook(Thread hook) {
        SecurityManager sm = System.getSecurityManager();
        if (sm != null) {
            sm.checkPermission(new RuntimePermission("shutdownHooks"));
        }
        ApplicationShutdownHooks.add(hook);
    }

    /**
     * 取消注册先前注册的虚拟机关闭钩子。<p>
     *
     * @param hook 要移除的钩子
     * @return 如果指定的钩子先前已注册并成功取消注册，则返回 <tt>true</tt>，
     * 否则返回 <tt>false</tt>
     *
     * @throws  IllegalStateException
     *          如果虚拟机已经在关闭过程中
     *
     * @throws  SecurityException
     *          如果存在安全管理器且它拒绝
     *          <tt>{@link RuntimePermission}("shutdownHooks")</tt>
     *
     * @see #addShutdownHook
     * @see #exit(int)
     * @since 1.3
     */
    public boolean removeShutdownHook(Thread hook) {
        SecurityManager sm = System.getSecurityManager();
        if (sm != null) {
            sm.checkPermission(new RuntimePermission("shutdownHooks"));
        }
        return ApplicationShutdownHooks.remove(hook);
    }

    /**
     * 强制终止当前运行的 Java 虚拟机。此方法从不正常返回。
     *
     * <p> 此方法应极其谨慎地使用。与 {@link #exit exit} 方法不同，
     * 此方法不会导致关闭钩子启动。如果关闭序列已经启动，
     * 则此方法不会等待任何正在运行的关闭钩子完成其工作。
     *
     * @param  status
     *         终止状态。按照惯例，非零状态代码表示异常终止。
     *         如果 {@link Runtime#exit exit}（等效于 {@link System#exit(int) System.exit}）
     *         方法已被调用，则此状态代码将覆盖传递给该方法的状态代码。
     *
     * @throws SecurityException
     *         如果存在安全管理器且其 {@link SecurityManager#checkExit checkExit}
     *         方法不允许使用指定状态退出
     *
     * @see #exit
     * @see #addShutdownHook
     * @see #removeShutdownHook
     * @since 1.3
     */
    public void halt(int status) {
        SecurityManager sm = System.getSecurityManager();
        if (sm != null) {
            sm.checkExit(status);
        }
        Shutdown.beforeHalt();
        Shutdown.halt(status);
    }

    /**
     * 抛出 {@code UnsupportedOperationException}。
     *
     * @param value 被忽略
     *
     * @deprecated 此方法最初设计用于启用或禁用退出时运行终结器。
     * 退出时运行终结器默认是禁用的。如果启用，则在 Java 运行时退出之前，
     * 所有尚未自动调用终结器的对象的终结器都将运行。
     * 这种行为本质上是不安全的。它可能导致在其他线程同时操作这些对象时
     * 在活动对象上调用终结器，从而导致不稳定的行为或死锁。
     *
     * @since JDK1.1
     */
    @Deprecated
    public static void runFinalizersOnExit(boolean value) {
        throw new UnsupportedOperationException();
    }

    /**
     * 在单独的进程中执行指定的字符串命令。
     *
     * <p>这是一个便捷方法。形式为 <tt>exec(command)</tt> 的调用
     * 的行为与调用 <tt>{@link #exec(String, String[], File) exec}(command, null, null)</tt>
     * 完全相同。
     *
     * @param   command   指定的系统命令
     *
     * @return  用于管理子进程的新 {@link Process} 对象
     *
     * @throws  SecurityException
     *          如果存在安全管理器且其 {@link SecurityManager#checkExec checkExec}
     *          方法不允许创建子进程
     *
     * @throws  IOException
     *          如果发生 I/O 错误
     *
     * @throws  NullPointerException
     *          如果 <code>command</code> 为 <code>null</code>
     *
     * @throws  IllegalArgumentException
     *          如果 <code>command</code> 为空
     *
     * @see     #exec(String[], String[], File)
     * @see     ProcessBuilder
     */
    public Process exec(String command) throws IOException {
        return exec(command, null, null);
    }

    /**
     * 在单独的进程中使用指定的环境执行指定的字符串命令。
     *
     * <p>这是一个便捷方法。形式为 <tt>exec(command, envp)</tt> 的调用
     * 的行为与调用 <tt>{@link #exec(String, String[], File) exec}(command, envp, null)</tt>
     * 完全相同。
     *
     * @param   command   指定的系统命令
     *
     * @param   envp      字符串数组，其中每个元素都具有格式为
     *                    <i>name</i>=<i>value</i> 的环境变量设置，
     *                    或者如果子进程应该继承当前进程的环境，则为 <tt>null</tt>
     *
     * @return  用于管理子进程的新 {@link Process} 对象
     *
     * @throws  SecurityException
     *          如果存在安全管理器且其 {@link SecurityManager#checkExec checkExec}
     *          方法不允许创建子进程
     *
     * @throws  IOException
     *          如果发生 I/O 错误
     *
     * @throws  NullPointerException
     *          如果 <code>command</code> 为 <code>null</code>，
     *          或者 <code>envp</code> 的元素之一为 <code>null</code>
     *
     * @throws  IllegalArgumentException
     *          如果 <code>command</code> 为空
     *
     * @see     #exec(String[], String[], File)
     * @see     ProcessBuilder
     */
    public Process exec(String command, String[] envp) throws IOException {
        return exec(command, envp, null);
    }

    /**
     * 在单独的进程中使用指定的环境和工作目录执行指定的字符串命令。
     *
     * <p>这是一个便捷方法。形式为 <tt>exec(command, envp, dir)</tt> 的调用
     * 的行为与调用 <tt>{@link #exec(String[], String[], File) exec}(cmdarray, envp, dir)</tt>
     * 完全相同，其中 <code>cmdarray</code> 是 <code>command</code> 中所有标记的数组。
     *
     * <p>更准确地说，<code>command</code> 字符串使用通过调用
     * <code>new {@link StringTokenizer}(command)</code> 创建的 {@link StringTokenizer}
     * 分解为标记，不对字符类别进行进一步修改。
     * 然后将分词器产生的标记按相同顺序放置在新的字符串数组 <code>cmdarray</code> 中。
     *
     * @param   command   指定的系统命令
     *
     * @param   envp      字符串数组，其中每个元素都具有格式为
     *                    <i>name</i>=<i>value</i> 的环境变量设置，
     *                    或者如果子进程应该继承当前进程的环境，则为 <tt>null</tt>
     *
     * @param   dir       子进程的工作目录，或者如果子进程应该继承
     *                    当前进程的工作目录，则为 <tt>null</tt>
     *
     * @return  用于管理子进程的新 {@link Process} 对象
     *
     * @throws  SecurityException
     *          如果存在安全管理器且其 {@link SecurityManager#checkExec checkExec}
     *          方法不允许创建子进程
     *
     * @throws  IOException
     *          如果发生 I/O 错误
     *
     * @throws  NullPointerException
     *          如果 <code>command</code> 为 <code>null</code>，
     *          或者 <code>envp</code> 的元素之一为 <code>null</code>
     *
     * @throws  IllegalArgumentException
     *          如果 <code>command</code> 为空
     *
     * @see     ProcessBuilder
     * @since 1.3
     */
    public Process exec(String command, String[] envp, File dir)
        throws IOException {
        if (command.isEmpty())
            throw new IllegalArgumentException("Empty command");

        StringTokenizer st = new StringTokenizer(command);
        String[] cmdarray = new String[st.countTokens()];
        for (int i = 0; st.hasMoreTokens(); i++)
            cmdarray[i] = st.nextToken();
        return exec(cmdarray, envp, dir);
    }

    /**
     * 在单独的进程中执行指定的命令和参数。
     *
     * <p>这是一个便捷方法。形式为 <tt>exec(cmdarray)</tt> 的调用
     * 的行为与调用 <tt>{@link #exec(String[], String[], File) exec}(cmdarray, null, null)</tt>
     * 完全相同。
     *
     * @param   cmdarray  包含要调用的命令及其参数的数组
     *
     * @return  用于管理子进程的新 {@link Process} 对象
     *
     * @throws  SecurityException
     *          如果存在安全管理器且其 {@link SecurityManager#checkExec checkExec}
     *          方法不允许创建子进程
     *
     * @throws  IOException
     *          如果发生 I/O 错误
     *
     * @throws  NullPointerException
     *          如果 <code>cmdarray</code> 为 <code>null</code>，
     *          或者 <code>cmdarray</code> 的元素之一为 <code>null</code>
     *
     * @throws  IndexOutOfBoundsException
     *          如果 <code>cmdarray</code> 是空数组（长度为 <code>0</code>）
     *
     * @see     ProcessBuilder
     */
    public Process exec(String cmdarray[]) throws IOException {
        return exec(cmdarray, null, null);
    }

    /**
     * 在单独的进程中使用指定的环境执行指定的命令和参数。
     *
     * <p>这是一个便捷方法。形式为 <tt>exec(cmdarray, envp)</tt> 的调用
     * 的行为与调用 <tt>{@link #exec(String[], String[], File) exec}(cmdarray, envp, null)</tt>
     * 完全相同。
     *
     * @param   cmdarray  包含要调用的命令及其参数的数组
     *
     * @param   envp      字符串数组，其中每个元素都具有格式为
     *                    <i>name</i>=<i>value</i> 的环境变量设置，
     *                    或者如果子进程应该继承当前进程的环境，则为 <tt>null</tt>
     *
     * @return  用于管理子进程的新 {@link Process} 对象
     *
     * @throws  SecurityException
     *          如果存在安全管理器且其 {@link SecurityManager#checkExec checkExec}
     *          方法不允许创建子进程
     *
     * @throws  IOException
     *          如果发生 I/O 错误
     *
     * @throws  NullPointerException
     *          如果 <code>cmdarray</code> 为 <code>null</code>，
     *          或者 <code>cmdarray</code> 的元素之一为 <code>null</code>，
     *          或者 <code>envp</code> 的元素之一为 <code>null</code>
     *
     * @throws  IndexOutOfBoundsException
     *          如果 <code>cmdarray</code> 是空数组（长度为 <code>0</code>）
     *
     * @see     ProcessBuilder
     */
    public Process exec(String[] cmdarray, String[] envp) throws IOException {
        return exec(cmdarray, envp, null);
    }


    /**
     * 在单独的进程中使用指定的环境和工作目录执行指定的命令和参数。
     *
     * <p>给定表示命令行标记的字符串数组 <code>cmdarray</code> 和
     * 表示"环境"变量设置的字符串数组 <code>envp</code>，
     * 此方法创建一个新进程来执行指定的命令。
     *
     * <p>此方法检查 <code>cmdarray</code> 是否为有效的操作系统命令。
     * 哪些命令有效取决于系统，但至少命令必须是非空的非空字符串列表。
     *
     * <p>如果 <tt>envp</tt> 为 <tt>null</tt>，子进程继承当前进程的环境设置。
     *
     * <p>在某些操作系统上启动进程可能需要最少的系统相关环境变量集。
     * 因此，子进程可能继承指定环境之外的其他环境变量设置。
     *
     * <p>{@link ProcessBuilder#start()} 现在是使用修改的环境启动进程的首选方式。
     *
     * <p>新子进程的工作目录由 <tt>dir</tt> 指定。
     * 如果 <tt>dir</tt> 为 <tt>null</tt>，子进程继承当前进程的当前工作目录。
     *
     * <p>如果存在安全管理器，则使用数组 <code>cmdarray</code> 的第一个组件
     * 作为参数调用其 {@link SecurityManager#checkExec checkExec} 方法。
     * 这可能导致抛出 {@link SecurityException}。
     *
     * <p>启动操作系统进程高度依赖于系统。可能出错的许多事情包括：
     * <ul>
     * <li>找不到操作系统程序文件。
     * <li>对程序文件的访问被拒绝。
     * <li>工作目录不存在。
     * </ul>
     *
     * <p>在这种情况下将抛出异常。异常的确切性质取决于系统，
     * 但它始终是 {@link IOException} 的子类。
     *
     *
     * @param   cmdarray  包含要调用的命令及其参数的数组
     *
     * @param   envp      字符串数组，其中每个元素都具有格式为
     *                    <i>name</i>=<i>value</i> 的环境变量设置，
     *                    或者如果子进程应该继承当前进程的环境，则为 <tt>null</tt>
     *
     * @param   dir       子进程的工作目录，或者如果子进程应该继承
     *                    当前进程的工作目录，则为 <tt>null</tt>
     *
     * @return  用于管理子进程的新 {@link Process} 对象
     *
     * @throws  SecurityException
     *          如果存在安全管理器且其 {@link SecurityManager#checkExec checkExec}
     *          方法不允许创建子进程
     *
     * @throws  IOException
     *          如果发生 I/O 错误
     *
     * @throws  NullPointerException
     *          如果 <code>cmdarray</code> 为 <code>null</code>，
     *          或者 <code>cmdarray</code> 的元素之一为 <code>null</code>，
     *          或者 <code>envp</code> 的元素之一为 <code>null</code>
     *
     * @throws  IndexOutOfBoundsException
     *          如果 <code>cmdarray</code> 是空数组（长度为 <code>0</code>）
     *
     * @see     ProcessBuilder
     * @since 1.3
     */
    public Process exec(String[] cmdarray, String[] envp, File dir)
        throws IOException {
        return new ProcessBuilder(cmdarray)
            .environment(envp)
            .directory(dir)
            .start();
    }

    /**
     * 返回 Java 虚拟机可用的处理器数量。
     *
     * <p> 此值可能在虚拟机的特定调用期间发生变化。
     * 因此，对可用处理器数量敏感的应用程序应偶尔轮询此属性并适当调整其资源使用。</p>
     *
     * @return  虚拟机可用的最大处理器数量；永远不小于一
     * @since 1.4
     */
    public native int availableProcessors();

    /**
     * 返回 Java 虚拟机中的空闲内存量。
     * 调用 <code>gc</code> 方法可能会导致 <code>freeMemory</code> 返回的值增加。
     *
     * @return  当前可用于未来分配对象的内存总量的近似值，以字节为单位
     */
    public native long freeMemory();

    /**
     * 返回 Java 虚拟机中的内存总量。
     * 此方法返回的值可能会随时间变化，具体取决于主机环境。
     * <p>
     * 请注意，保存任何给定类型对象所需的内存量可能依赖于具体实现。
     *
     * @return  当前可用于当前和未来对象的内存总量，以字节为单位
     */
    public native long totalMemory();

    /**
     * 返回 Java 虚拟机将尝试使用的最大内存量。
     * 如果没有固有限制，则返回 {@link java.lang.Long#MAX_VALUE}。
     *
     * @return  虚拟机将尝试使用的最大内存量，以字节为单位
     * @since 1.4
     */
    public native long maxMemory();

    /**
     * 运行垃圾收集器。
     * 调用此方法建议 Java 虚拟机努力回收未使用的对象，
     * 以便使它们当前占用的内存可供快速重用。当从方法调用返回控制权时，
     * 虚拟机已尽最大努力回收所有丢弃的对象。
     * <p>
     * 名称 <code>gc</code> 代表"垃圾收集器"。
     * 虚拟机会根据需要在单独的线程中自动执行此回收过程，
     * 即使没有显式调用 <code>gc</code> 方法。
     * <p>
     * 方法 {@link System#gc()} 是调用此方法的常规和便捷方式。
     */
    public native void gc();

    /* Wormhole for calling java.lang.ref.Finalizer.runFinalization */
    private static native void runFinalization0();

    /**
     * 运行任何待终结对象的终结方法。
     * 调用此方法建议 Java 虚拟机努力运行已发现被丢弃但其 <code>finalize</code>
     * 方法尚未运行的对象的 <code>finalize</code> 方法。
     * 当从方法调用返回控制权时，虚拟机已尽最大努力完成所有未完成的终结。
     * <p>
     * 如果没有显式调用 <code>runFinalization</code> 方法，
     * 虚拟机会根据需要在单独的线程中自动执行终结过程。
     * <p>
     * 方法 {@link System#runFinalization()} 是调用此方法的常规和便捷方式。
     *
     * @see     java.lang.Object#finalize()
     */
    public void runFinalization() {
        runFinalization0();
    }

    /**
     * 启用/禁用指令跟踪。
     * 如果 <code>boolean</code> 参数为 <code>true</code>，
     * 此方法建议 Java 虚拟机在执行虚拟机中的每个指令时发出调试信息。
     * 此信息的格式以及发出信息的文件或其他输出流取决于主机环境。
     * 如果虚拟机不支持此功能，它可能会忽略此请求。
     * 跟踪输出的目标取决于系统。
     * <p>
     * 如果 <code>boolean</code> 参数为 <code>false</code>，
     * 此方法使虚拟机停止执行正在执行的详细指令跟踪。
     *
     * @param   on   <code>true</code> 启用指令跟踪；
     *               <code>false</code> 禁用此功能
     */
    public native void traceInstructions(boolean on);

    /**
     * 启用/禁用方法调用跟踪。
     * 如果 <code>boolean</code> 参数为 <code>true</code>，
     * 此方法建议 Java 虚拟机在调用虚拟机中的每个方法时发出调试信息。
     * 此信息的格式以及发出信息的文件或其他输出流取决于主机环境。
     * 如果虚拟机不支持此功能，它可能会忽略此请求。
     * <p>
     * 使用参数 false 调用此方法建议虚拟机停止发出每次调用的调试信息。
     *
     * @param   on   <code>true</code> 启用方法调用跟踪；
     *               <code>false</code> 禁用此功能
     */
    public native void traceMethodCalls(boolean on);

    /**
     * 加载由 filename 参数指定的本机库。filename 参数必须是绝对路径名。
     * （例如 <code>Runtime.getRuntime().load("/home/avh/lib/libX11.so");</code>）。
     *
     * 如果 filename 参数在去除任何平台特定的库前缀、路径和文件扩展名后，
     * 指示一个名称为（例如）L 的库，并且名为 L 的本机库与 VM 静态链接，
     * 则调用库导出的 JNI_OnLoad_L 函数，而不是尝试加载动态库。
     * 与参数匹配的文件名不必存在于文件系统中。有关更多详细信息，请参阅 JNI 规范。
     *
     * 否则，filename 参数以依赖于实现的方式映射到本机库映像。
     * <p>
     * 首先，如果存在安全管理器，则使用 <code>filename</code> 作为参数
     * 调用其 <code>checkLink</code> 方法。这可能导致安全异常。
     * <p>
     * 这类似于方法 {@link #loadLibrary(String)}，但它接受通用文件名作为参数
     * 而不仅仅是库名，允许加载任何本机代码文件。
     * <p>
     * 方法 {@link System#load(String)} 是调用此方法的常规和便捷方式。
     *
     * @param      filename   要加载的文件
     * @exception  SecurityException  如果存在安全管理器且其 <code>checkLink</code>
     *             方法不允许加载指定的动态库
     * @exception  UnsatisfiedLinkError  如果 filename 不是绝对路径名，
     *             本机库未与 VM 静态链接，或者主机系统无法将库映射到本机库映像
     * @exception  NullPointerException 如果 <code>filename</code> 为 <code>null</code>
     * @see        java.lang.Runtime#getRuntime()
     * @see        java.lang.SecurityException
     * @see        java.lang.SecurityManager#checkLink(java.lang.String)
     */
    @CallerSensitive
    public void load(String filename) {
        load0(Reflection.getCallerClass(), filename);
    }

    synchronized void load0(Class<?> fromClass, String filename) {
        SecurityManager security = System.getSecurityManager();
        if (security != null) {
            security.checkLink(filename);
        }
        if (!(new File(filename).isAbsolute())) {
            throw new UnsatisfiedLinkError(
                "Expecting an absolute path of the library: " + filename);
        }
        ClassLoader.loadLibrary(fromClass, filename, true);
    }

    /**
     * 加载由 <code>libname</code> 参数指定的本机库。
     * <code>libname</code> 参数不得包含任何平台特定的前缀、文件扩展名或路径。
     * 如果名为 <code>libname</code> 的本机库与 VM 静态链接，
     * 则调用库导出的 JNI_OnLoad_<code>libname</code> 函数。
     * 有关更多详细信息，请参阅 JNI 规范。
     *
     * 否则，libname 参数从系统库位置加载，
     * 并以依赖于实现的方式映射到本机库映像。
     * <p>
     * 首先，如果存在安全管理器，则使用 <code>libname</code> 作为参数
     * 调用其 <code>checkLink</code> 方法。这可能导致安全异常。
     * <p>
     * 方法 {@link System#loadLibrary(String)} 是调用此方法的常规和便捷方式。
     * 如果要在类的实现中使用本机方法，标准策略是将本机代码放在库文件中
     * （称为 <code>LibFile</code>），然后放置一个静态初始化器：
     * <blockquote><pre>
     * static { System.loadLibrary("LibFile"); }
     * </pre></blockquote>
     * 在类声明中。当类被加载和初始化时，本机方法所需的本机代码实现也将被加载。
     * <p>
     * 如果使用相同的库名多次调用此方法，第二次和后续调用将被忽略。
     *
     * @param      libname   库的名称
     * @exception  SecurityException  如果存在安全管理器且其 <code>checkLink</code>
     *             方法不允许加载指定的动态库
     * @exception  UnsatisfiedLinkError 如果 libname 参数包含文件路径，
     *             本机库未与 VM 静态链接，或者主机系统无法将库映射到本机库映像
     * @exception  NullPointerException 如果 <code>libname</code> 为 <code>null</code>
     * @see        java.lang.SecurityException
     * @see        java.lang.SecurityManager#checkLink(java.lang.String)
     */
    @CallerSensitive
    public void loadLibrary(String libname) {
        loadLibrary0(Reflection.getCallerClass(), libname);
    }

    synchronized void loadLibrary0(Class<?> fromClass, String libname) {
        SecurityManager security = System.getSecurityManager();
        if (security != null) {
            security.checkLink(libname);
        }
        if (libname.indexOf((int)File.separatorChar) != -1) {
            throw new UnsatisfiedLinkError(
    "Directory separator should not appear in library name: " + libname);
        }
        ClassLoader.loadLibrary(fromClass, libname, false);
    }

    /**
     * 创建输入流的本地化版本。此方法接受一个 <code>InputStream</code>
     * 并返回一个在所有方面都等效于参数的 <code>InputStream</code>，
     * 除了它是本地化的：当从流中读取本地字符集中的字符时，
     * 它们会自动从本地字符集转换为 Unicode。
     * <p>
     * 如果参数已经是本地化流，则可以将其作为结果返回。
     *
     * @param      in 要本地化的 InputStream
     * @return     本地化的输入流
     * @see        java.io.InputStream
     * @see        java.io.BufferedReader#BufferedReader(java.io.Reader)
     * @see        java.io.InputStreamReader#InputStreamReader(java.io.InputStream)
     * @deprecated 从 JDK&nbsp;1.1 开始，将本地编码中的字节流转换为 Unicode 中的字符流的
     * 首选方式是通过 <code>InputStreamReader</code> 和 <code>BufferedReader</code> 类。
     */
    @Deprecated
    public InputStream getLocalizedInputStream(InputStream in) {
        return in;
    }

    /**
     * 创建输出流的本地化版本。此方法接受一个 <code>OutputStream</code>
     * 并返回一个在所有方面都等效于参数的 <code>OutputStream</code>，
     * 除了它是本地化的：当 Unicode 字符写入流时，
     * 它们会自动转换为本地字符集。
     * <p>
     * 如果参数已经是本地化流，则可以将其作为结果返回。
     *
     * @deprecated 从 JDK&nbsp;1.1 开始，将 Unicode 字符流转换为本地编码中的字节流的
     * 首选方式是通过 <code>OutputStreamWriter</code>、<code>BufferedWriter</code>
     * 和 <code>PrintWriter</code> 类。
     *
     * @param      out 要本地化的 OutputStream
     * @return     本地化的输出流
     * @see        java.io.OutputStream
     * @see        java.io.BufferedWriter#BufferedWriter(java.io.Writer)
     * @see        java.io.OutputStreamWriter#OutputStreamWriter(java.io.OutputStream)
     * @see        java.io.PrintWriter#PrintWriter(java.io.OutputStream)
     */
    @Deprecated
    public OutputStream getLocalizedOutputStream(OutputStream out) {
        return out;
    }

}
